#include <scene_manager.h>
#include <fstream>
#include <sstream>
#include <obj_parser.h>
#include <imgui.h>

void SceneManager::createScene(const std::filesystem::path& path) {
    std::ifstream infile(path);
    if (!infile.is_open()) {
        std::string error = "failed to open file " + path.string();
        throw std::runtime_error(error);
    }

    mParentPath = std::filesystem::canonical(path).parent_path();

    std::string line;
    while (std::getline(infile, line)) {
        std::stringstream lineStream(line);
        std::string token;
        lineStream >> token;
        if (token == "Scene") {
            mScenes.push_back(parseScene(infile));
        }
        else if (token == "") {
            
        }
        else {
            throw std::runtime_error("Parse error, can not find Scene. Please check the t3sr file");
        }
    }
}

Scene SceneManager::parseScene(std::ifstream& infile) const {
    std::string line;
    Scene scene;
    while (std::getline(infile, line)) {
        std::stringstream lineStream(line);
        std::string token;
        lineStream >> token;
        if (token == "Name") {
            lineStream >> scene.name;
        }
        else if (token == "Model") {
            scene.models.push_back(parseModel(infile));
        }
        else if (token == "Light") {
            scene.lights.push_back(parseLight(lineStream));
        }
        else if (token == "") {

        }
        else {
            return scene;
        }
    }

    return scene;
}

Model SceneManager::parseModel(std::istream& stream) const {
    Model model;
    std::string line;
    while (std::getline(stream, line)) {
        std::stringstream lineStream(line);
        std::string token;
        lineStream >> token;
        if (token == "ModelFile") {
            lineStream >> token;
            model.mesh = ObjParser::Parse(std::filesystem::path(mParentPath).append(token));
        }
        else if (token == "ModelToWorld") {
            while (lineStream >> token) {
                if (token == "sca") {
                    lineStream >> token;
                    model.scale = ObjParser::parseVec<Vec3f>(token, '_');
                }
                else if (token == "rot") {
                    lineStream >> token;
                    model.rotate = ObjParser::parseVec<Vec3f>(token, '_');
                }
                else if (token == "pos") {
                    lineStream >> token;
                    model.position = ObjParser::parseVec<Vec3f>(token, '_');
                }
                else {
                    break;
                }
            }
        }
        else if (token == "Texture") {
            lineStream >> token;
            Texture texture;
            texture.createTexture(std::filesystem::path(mParentPath).append(token).string());
            model.texture = std::move(texture);
        }
        else {
            return model;
        }
    }

    return model;
}

std::shared_ptr<Light> SceneManager::parseLight(std::istream& stream) const {
    std::shared_ptr<Light> light;
    Vec3f lightPos;
    Color4f lightColor;
    std::string token;
    while (stream >> token) {
        if (token == "pos") {
            stream >> token;
            lightPos = ObjParser::parseVec<Vec3f>(token, '_');
        }
        else if (token == "color") {
            stream >> token;
            lightColor = ObjParser::parseVec<Color4f>(token, '_') / 255.0f;
        }
        else {
            throw std::runtime_error("Parse error");
        }
    }

    return std::make_shared<PointLight>(lightPos, lightColor);
}